//
//  StepViewModel.swift
//  MoyoungHome
//
//  Created by 李然 on 2022/9/1.
//

import MYModule
import RxCocoa
import RxSwift
import SwiftDate
import Foundation

open class ActivityHomeViewModel: ViewModel, ViewModelType {
    
    private var providerDate: Date?
    
    public var inPut: Input?
    
    public var outPut: Output?
    
    
	public struct Input {
        public var provider: StepProvider?
        public let viewWillAppear:ControlEvent<Bool>
        
        public init(viewWillAppear:ControlEvent<Bool>) {
            self.viewWillAppear = viewWillAppear
        }
	}

	public struct Output {
        
        public let providerRelay: BehaviorRelay<StepProvider?>
        
        public let dayChart: BehaviorRelay<StepDataChartViewModel?>
        public let weekChart: BehaviorRelay<StepDataChartViewModel?>
        public let montChart: BehaviorRelay<StepDataChartViewModel?>
    
        public let totalTrainingTimes: BehaviorRelay<Int>
        public let totalTrainingDurations: BehaviorRelay<Int>
        public let totalTrainingCalories: BehaviorRelay<Int>
        
        public let workoutsRocords: BehaviorRelay<[TrainingModel]>
		public let compareDataSource: BehaviorRelay<(index: Int, percentage: Int)>
	}
    
    public override init() {
        super.init()
        
        /// 进入前台通知,延时一秒是因为给SDK setTime 留时间
        NotificationCenter.default.rx.notification(UIApplication.willEnterForegroundNotification).take(until: self.rx.deallocated).delay(.seconds(1), scheduler: MainScheduler()).subscribe(onNext: {[weak self] noti in
            
            let provider = self?.providerObserver(input: self?.inPut)
            self?.outPut?.providerRelay.accept(provider)
            
        }).disposed(by: rx.disposeBag)
        
        
        NotificationCenter.default.rx.notification(.kUpdateUINotification).take(until: self.rx.deallocated).subscribe(onNext: {[weak self] in
            
                self?.notifactionAction(noti: $0)
            
        }).disposed(by: rx.disposeBag)
        
        
    }
    
    func notifactionAction(noti: Notification) {
        
        guard let dict = noti.userInfo as? [String: Any], let type = dict["type"] as? NotifactionType else { return }
        
        switch type {
            
        case .activity:
            
            /// 更新数据
            let provider = self.providerObserver(input: self.inPut)
            self.outPut?.providerRelay.accept(provider)
            
        default:
            break
            
        }
        
    }
    
    
	open func transform(input: Input) -> Output {
        
        self.inPut = input
        
        let providerRelay = BehaviorRelay<StepProvider?>(value: nil)
    
        let dayChart = BehaviorRelay<StepDataChartViewModel?>(value: nil)
        let weekChart = BehaviorRelay<StepDataChartViewModel?>(value: nil)
        let monthChart = BehaviorRelay<StepDataChartViewModel?>(value: nil)
        
        input.viewWillAppear.map {[weak self] animted ->StepProvider? in
              
            return self?.providerObserver(input: input)
             
        }.bind(to: providerRelay).disposed(by: rx.disposeBag)
        

        createChat(with: providerRelay, chartReplay: dayChart, type: .day)
        createChat(with: providerRelay, chartReplay: weekChart, type: .week)
        createChat(with: providerRelay, chartReplay: monthChart, type: .month)
        
        let totalTrainingTimes = BehaviorRelay<Int>(value: 0)
        let totalTrainingDurations = BehaviorRelay<Int>(value: 0)
        let totalTrainingCalories = BehaviorRelay<Int>(value: 0)
        
        let workoutsRocords = BehaviorRelay<[TrainingModel]>(value: [])
        let compareDataSource = BehaviorRelay<(index: Int, percentage: Int)>(value: (0, 0))
        
        input.viewWillAppear.map {[weak self] animted ->[TrainingModel] in
            
            guard let provider = self?.providerObserver(input: input) else {
                return []
            }
              
            let trainingModels = [TrainingModel].deserialize(from: provider.date) ?? []
                return trainingModels
              
        }.subscribe(onNext: { trainingModels in
            
            let times: Int = trainingModels.count
            var durations: Int = 0
            var calories: Int = 0
            trainingModels.forEach { model in
                
                calories = calories + model.kcal
                durations = durations + model.vaildTime
    
            }
            
            workoutsRocords.accept(trainingModels)

            totalTrainingTimes.accept(times)
            totalTrainingCalories.accept(calories)
            totalTrainingDurations.accept(durations/60)
            
        }).disposed(by: rx.disposeBag)
        
        
        input.viewWillAppear.map {[weak self] animted ->(index: Int, percentage: Int) in
            
            guard let provider = self?.providerObserver(input: input) else {
                return (0, 0)
            }
            return provider.getCompareResult()
            
        }.bind(to: compareDataSource).disposed(by: rx.disposeBag)
        
        
        
        /// 更新需要从指令获取的数据
        let stepArchiveDatasSubject = BehaviorRelay<Bool>(value: false)
        let stepDataUpdateSubject = BehaviorRelay<Bool>(value: false)
        
       Observable.combineLatest(stepArchiveDatasSubject, stepDataUpdateSubject).share().map { (update, update1) ->Bool in
           
           return update && update1
            
       }.subscribe(onNext: {[weak self] in
           
           if $0 == false {
               return
           }
           
           let provider = providerRelay.value
           self?.providerDate = provider?.date
           
           providerRelay.accept(provider)
           
       }).disposed(by: rx.disposeBag)
        
        
        providerRelay.filter {[weak self] in
            
            guard let provider = $0 else {
                 return false
             }
             
             // 只在今天才去同步指令数据
             if !provider.date.isToday {
                 return false
             }
             
             guard let providerDate = self?.providerDate else {
                 return true
             }

            return providerDate.day != provider.date.day
            
        }.subscribe(onNext: { provider in
            
            guard let provider = provider else {
                return
            }
            
            
            // 获取15天步数归档
            BluetoothManager.shared.getStepArchiveDatas(of: provider.date, backward: 15, forcedUpdate: false) {
                
                stepArchiveDatasSubject.accept(true)
                
            }
            
            // 15天活动历史记录
            BluetoothManager.shared.getTrainingDatas(of: provider.date, backward: 15, forcedUpdate: false) {
                
                stepDataUpdateSubject.accept(true)
            }
            
            
        }).disposed(by: rx.disposeBag)
        
      
       
		let outPut = Output(providerRelay: providerRelay,
                      dayChart: dayChart,
                      weekChart: weekChart,
                      montChart: monthChart,
                      totalTrainingTimes: totalTrainingTimes,
                      totalTrainingDurations: totalTrainingDurations,
                      totalTrainingCalories: totalTrainingCalories,
                      workoutsRocords: workoutsRocords,
                      compareDataSource: compareDataSource)
        
        self.outPut = outPut
        
        return outPut
    }
    
    
   
    
    open func providerObserver(input: Input?) ->StepProvider {
        guard let provider = input?.provider else {
             
             return StepProvider(date: Date())
         }
         return provider
    }
    
    
    open func createChat(with providerReplay: BehaviorRelay<StepProvider?>, chartReplay: BehaviorRelay<StepDataChartViewModel?>, type: DataChartType) {
        
        providerReplay.map { provider ->StepDataChartViewModel? in
            
            guard let provider = provider else {
                return nil
            }
            
            var dataSource = [Double]()
            if type == .day {
                dataSource = provider.curDayDetail.map { i in Double(i) }
            } else if type == .week {
                dataSource = provider.weekRecord.map { model in Double(model.step) }
            } else if type == .month {
                dataSource = provider.monthRecord.map { model in Double(model.step) }
            }
            var defaultValue: Double = 0
            defaultValue = Double(provider.curDayStepRecord.step)
                
            let viewModel = StepDataChartViewModel(date: provider.date,
                                                   defaultValue: defaultValue,
                                                   dataSource: dataSource,
                                                   chartType: type)
    
            
            return viewModel
            
        }.bind(to: chartReplay).disposed(by: rx.disposeBag)
        
    }
}
